/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.hamacekj.geometr.internalplugins;

import cz.hamacekj.geometr.plugin.ConstructionObject;
import cz.hamacekj.geometr.plugin.ConstructionPlugin;
import cz.hamacekj.geometr.plugin.IPoint;
import cz.hamacekj.geometr.plugin.IPointObject;
import cz.hamacekj.geometr.plugin.IRayObject;
import cz.hamacekj.geometr.plugin.IToolBox;
import cz.hamacekj.geometr.plugin.InputParameters;
import cz.hamacekj.geometr.plugin.InputParametersInterface;
import cz.hamacekj.geometr.plugin.ParameterItem;
import cz.hamacekj.geometr.plugin.ParameterObject;
import cz.hamacekj.geometr.plugin.ParameterString;
import cz.hamacekj.geometr.plugin.ParameterValue;
import cz.hamacekj.geometr.plugin.PrimitiveObject;
import cz.hamacekj.geometr.plugin.ValueArgument;
import java.util.HashSet;
import java.util.Set;
import javax.swing.ImageIcon;

/**
 * Plugin vytvoření úhlu.
 * @author hamacekh
 */
public class AnglePlugin implements ConstructionPlugin {
    private String error = null;
    private IToolBox toolbox;

    public AnglePlugin() {
    }

    public AnglePlugin(IToolBox toolbox) {
        this.toolbox = toolbox;
    }
    
    
    public void setToolbox(IToolBox toolbox){
        this.toolbox = toolbox;
    }
    
    @Override
    public String getPluginName() {
        return "Úhel";
    }

    @Override
    public InputParametersInterface[] getPossibleParameters() {
        InputParametersInterface[] res = { new TwoPointsAngleParameters(),
        new ThreePointsAngleParameters()};
        return res;
    }

    @Override
    public ImageIcon getIcon() {
        ImageIcon icon = new ImageIcon("images/uhel.png");
        return icon;
    }

    @Override
    public ConstructionObject[] createConstructionObject(InputParametersInterface parametersType, ConstructionObject[] objects, ValueArgument[] values) {
        if(parametersType instanceof TwoPointsAngleParameters || parametersType instanceof ThreePointsAngleParameters){
            String name = values[0].getRealInput();
            final String realName;
            ConstructionObject firstPointObject = objects[0];
            ConstructionObject vertexPointObject = objects[1];
            IPointObject firstPoint = (IPointObject)firstPointObject.getPrimitiveObjects().iterator().next();
            IPointObject vertexPoint = (IPointObject)vertexPointObject.getPrimitiveObjects().iterator().next();
            final String firstPointName = firstPointObject.getLabel();
            final String vertexPointName = vertexPointObject.getLabel();
            final String newPointName = values[1].getRealInput();
            if(name.isEmpty()){
                realName = firstPointName+vertexPointName+newPointName;
            }else{
                realName = name;
            }
            final double angle = values[2].getValue();
            if(Double.isNaN(angle) || angle < 0 || angle > 180){
                this.error = "Nesprávně zadaný úhel";
                return null;
            }
            IPoint X1 = getThirdPoint(firstPoint.getPoint(), vertexPoint.getPoint(), angle);
            IPoint X2 = getThirdPoint(firstPoint.getPoint(), vertexPoint.getPoint(), -angle);
            if(parametersType instanceof TwoPointsAngleParameters){
                IPointObject X1Object = toolbox.createPointObject(X1);
                IPointObject X2Object = toolbox.createPointObject(X2);
                IRayObject baseRay = toolbox.createRayObject(vertexPoint.getPoint(), firstPoint.getPoint());
                IRayObject firstRay = toolbox.createRayObject(vertexPoint.getPoint(), X1);
                IRayObject secondRay = toolbox.createRayObject(vertexPoint.getPoint(), X2);
                Set<PrimitiveObject> firstSet = new HashSet<>();
                firstSet.add(firstRay);
                Set<PrimitiveObject> secondSet = new HashSet<>();
                secondSet.add(secondRay);
                Set<PrimitiveObject> pointSet1 = new HashSet<>();
                pointSet1.add(X1Object);
                Set<PrimitiveObject> pointSet2 = new HashSet<>();
                pointSet2.add(X2Object);
                ConstructionObject[] res = new ConstructionObject[4];
                res[0] = toolbox.createConstructionObject(vertexPointName+newPointName+"1", false, firstSet,
                        "<Úhel> "+realName+", "+"|<Úhel> "+realName+"| = "+angle+"°");
                res[1] = toolbox.createConstructionObject(vertexPointName+newPointName+"2", false, secondSet,
                        "<Úhel> "+realName+", "+"|<Úhel> "+realName+"| = "+angle+"°");
                res[2] = toolbox.createConstructionObject(newPointName+"1", true, pointSet1, newPointName+"1");
                res[3] = toolbox.createConstructionObject(newPointName+"2", true, pointSet2, newPointName+"2");
                return res;
            }else{
                assert parametersType instanceof ThreePointsAngleParameters;
                IPoint targetHalf = ((IPointObject)objects[2].getPrimitiveObjects().iterator().next()).getPoint();
                IPointObject XObject = toolbox.distance(X1, targetHalf) < toolbox.distance(X2, targetHalf)
                        ? toolbox.createPointObject(X1) : toolbox.createPointObject(X2);
                
                IRayObject baseRay = toolbox.createRayObject(vertexPoint.getPoint(), firstPoint.getPoint());
                IRayObject ray = toolbox.createRayObject(vertexPoint.getPoint(), XObject.getPoint());
                Set<PrimitiveObject> set = new HashSet<>();
                set.add(ray);
                Set<PrimitiveObject> pointSet = new HashSet<>();
                pointSet.add(XObject);
                ConstructionObject[] res = new ConstructionObject[2];
                res[0] = toolbox.createConstructionObject(vertexPointName+newPointName, false, set,
                        "<Úhel> "+realName+", "+"|<Úhel> "+realName+"| = "+angle+"°");
                res[1] = toolbox.createConstructionObject(newPointName, true, pointSet, newPointName);
                return res;
            }
        }
        return null;
    }
    
    private IPoint getThirdPoint(IPoint first, IPoint vertex, double angle){
        double vx = first.getX() - vertex.getX();
        double vy = first.getY() - vertex.getY();
        double rad = angle * Math.PI / 180;
        double sx = vx * Math.cos(rad) - vy * Math.sin(rad);
        double sy = vx * Math.sin(rad) - vy * Math.cos(rad);
        IPoint res = toolbox.createPoint(vertex.getX() + sx, vertex.getY() + sy);
        return res;
    }

    @Override
    public String getError() {
        return error;
    }
    
    private class TwoPointsAngleParameters extends InputParameters{

        @Override
        public String getParametersCaption() {
            return "Dva body a úhel";
        }

        @Override
        public ParameterItem[] getParameters() {
            ParameterItem[] res = new ParameterItem[6];
            res[0] = new ParameterValue() {

                @Override
                public String getCaption() {
                    return "Název";
                }
            };
            res[1] = new ParameterString() {

                @Override
                public String getText() {
                    return "Body a úhel";
                }
            };
            res[2] = new ParameterObject() {

                @Override
                public String getCaption() {
                    return "1. bod";
                }

                @Override
                public String[] getObjectNames() {
                    String[] res = { "Bod" };
                    return res;
                }
            };
            res[3] = new ParameterObject() {

                @Override
                public String getCaption() {
                    return "Vrchol";
                }

                @Override
                public String[] getObjectNames() {
                    String[] res = { "Bod" };
                    return res;
                }
            };
            res[4] = new ParameterValue() {

                @Override
                public String getCaption() {
                    return "Nový bod";
                }
            };
            res[5] = new ParameterValue() {

                @Override
                public String getCaption() {
                    return "Úhel (velikost)";
                }
            };
            return res;
        }

        @Override
        public String getHelp() {
            return "<h1>Vytvoření úhlu pomocí dvou bodů a jeho velikosti</h1>"
                    + "<p>Tato možnost vytvoří oba možné úhly zadané velikosti."
                    + "Vstupní parametry jsou:</p>"
                    + "<ul>"
                    + "<li> <b>Název</b> - Jméno nově vytvořeného úhlu. Pokud zůstane"
                    + " prázdné, bude se úhel jmenovat podle krajních bodů."
                    + "<li> <b>1. bod</b> - počáteční bod úhlu. Kdybych chtěl vytvořit úhel ABX, zde by bylo zadáno A"
                    + "<li> <b>Vrchol</b> - vrchol úhlu"
                    + "<li> <b>Nový bod</b> - název nově vytvořeného bodu. Když chci vytvořit"
                    + " úhel ABX, tak zde je zadáno X."
                    + "<li> <b>Úhel (velikost)</b> - velikost vytvářeného úhlu ve stupních.";
        }
        
        
        
    }
    
    private class ThreePointsAngleParameters extends InputParameters {

        @Override
        public String getParametersCaption() {
            return "Dva body, úhel, pol.";
        }

        @Override
        public ParameterItem[] getParameters() {
            ParameterItem[] res = new ParameterItem[8];
            
            res[0] = new ParameterValue() {

                @Override
                public String getCaption() {
                    return "Název";
                }
            };
            res[1] = new ParameterString() {

                @Override
                public String getText() {
                    return "Body a úhel";
                }
            };
            res[2] = new ParameterObject() {

                @Override
                public String getCaption() {
                    return "1. bod";
                }

                @Override
                public String[] getObjectNames() {
                    String[] res = { "Bod" };
                    return res;
                }
            };
            res[3] = new ParameterObject() {

                @Override
                public String getCaption() {
                    return "Vrchol";
                }

                @Override
                public String[] getObjectNames() {
                    String[] res = { "Bod" };
                    return res;
                }
            };
            res[4] = new ParameterValue() {

                @Override
                public String getCaption() {
                    return "Nový bod";
                }
            };
            res[5] = new ParameterValue() {

                @Override
                public String getCaption() {
                    return "Úhel (velikost)";
                }
            };
            res[6] = new ParameterString() {

                @Override
                public String getText() {
                    return "Polorovina";
                }
            };
            res[7] = new ParameterObject() {

                @Override
                public String getCaption() {
                    return "Bod";
                }

                @Override
                public String[] getObjectNames() {
                    String[] res = { "Bod" };
                    return res;
                }
            };
            return res;
        }

        @Override
        public String getHelp() {
            return "<h1>Vytvoření úhlu pomocí dvou bodů a jeho velikosti</h1>"
                    + "<p>Tato možnost vytvoří úhel zadané velikosti. Takové úhly jsou dva, "
                    + "bude vytvořen ten, který je v polorovině zadané prvním bodem, vrcholem a bodem poloroviny."
                    + "Vstupní parametry jsou:</p>"
                    + "<ul>"
                    + "<li> <b>Název</b> - Jméno nově vytvořeného úhlu. Pokud zůstane"
                    + " prázdné, bude se úhel jmenovat podle krajních bodů."
                    + "<li> <b>1. bod</b> - počáteční bod úhlu. Kdybych chtěl vytvořit úhel ABX, zde by bylo zadáno A"
                    + "<li> <b>Vrchol</b> - vrchol úhlu"
                    + "<li> <b>Nový bod</b> - název nově vytvořeného bodu. Když chci vytvořit"
                    + " úhel ABX, tak zde je zadáno X."
                    + "<li> <b>Úhel (velikost)</b> - velikost vytvářeného úhlu ve stupních."
                    + "<li> <b>Polorovina</b> - bod určující polorovinu ve které má být úhel vytvořen.";
        }
        
        
        
    }
    
}
